//
//  GLVertexAttribArrayBuffer.swift
//  learn-gl-es-swift
//
//  Created by LimitLiu on 2019/9/9.
//  Copyright © 2019 LimitLiu. All rights reserved.
//

import UIKit

class GLVertexAttribArrayBuffer: NSObject {
    var stride: GLsizei = GLsizei()
    var bufferSizeBytes: GLsizeiptr = GLsizeiptr()
    var name: GLuint = GLuint()
    deinit {
        guard name != 0 else {
            return
        }
        glDeleteBuffers(1, &name)
        name = GLuint()
    }
    
    init(
        attribStride stride: GLsizei,
        numberOfVertices count: GLsizei,
        data: UnsafeRawPointer,
        usage: GLenum
        ) {
        assert(stride > 0)
        assert(count > 0)
        self.stride = stride
        bufferSizeBytes = GLsizeiptr(stride * count)
        
        glGenBuffers(1, &name)
        glBindBuffer(GLenum(GL_ARRAY_BUFFER), name)
        glBufferData(GLenum(GL_ARRAY_BUFFER), bufferSizeBytes, data, usage)
        
        if name == 0 {
            assert(false, "Failed to generate name.")
        }
    }
    
    func reinit(attribStride stride: GLsizei, numberOfVertices count: GLsizei, data: UnsafeRawPointer) {
        assert(stride > 0)
        assert(count > 0)
        self.stride = stride
        bufferSizeBytes = GLsizeiptr(stride * count)
        glBindBuffer(GLenum(GL_ARRAY_BUFFER), name)
        glBufferData(GLenum(GL_ARRAY_BUFFER), bufferSizeBytes, data, GLenum(GL_DYNAMIC_DRAW))
        
        if name == 0 {
            assert(false, "Failed to generate name.")
        }
    }
    
    func prepareToDraw(
        attrib idx: GLuint,
        numberOfCoordinates count: GLint,
        attribOffset offset: GLsizeiptr,
        shouldEnable: Bool
        ) {
        assert(stride > 0)
        assert(count > 0 && count < 4)
        assert(name != 0, "Invalid name.")
        glBindBuffer(GLenum(GL_ARRAY_BUFFER), name)
        
        if shouldEnable {
            glEnableVertexAttribArray(idx)
        }
        
        glVertexAttribPointer(idx, count, GLenum(GL_FLOAT), GLboolean(GL_FALSE), stride, UnsafeRawPointer(bitPattern: offset))
        
        let err = glGetError()
        assert(err == GL_NO_ERROR, "GL error: \(err)")
    }
    
    func drawArray(mode: GLenum, startVertexIdx idx: GLint, numberOfVertices count: GLsizei) {
        assert(bufferSizeBytes >= GLsizei(idx + count) * stride, "Attempt to draw more vertex data than available.")
        glDrawArrays(mode, idx, count)
    }
}
